package com.wangsd.api.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wangsd.common.exception.BusinessErrorEnum;
import com.wangsd.common.exception.BusinessException;
import com.wangsd.common.jwt.TokenService;
import com.wangsd.common.utils.DateUtils;
import com.wangsd.common.utils.HttpClientUtils;
import com.wangsd.common.utils.MyDecimalUtils;
import com.wangsd.common.utils.ServletUtils;
import com.wangsd.common.utils.aes.AESUtil;
import com.wangsd.common.utils.rsa.RSAEncryptUtil;
import com.wangsd.member.entity.Member;
import com.wangsd.member.entity.MemberCoupon;
import com.wangsd.member.service.MemberCouponService;
import com.wangsd.system.entity.Coupon;
import com.wangsd.system.entity.Merchant;
import com.wangsd.system.entity.Trade;
import com.wangsd.system.service.CouponService;
import com.wangsd.system.service.MerchantService;
import com.wangsd.system.service.TradeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Inet4Address;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/**
 * 汇元支付服务层
 */
@Slf4j
@Service
public class HyPayService {
    @Autowired
    private CouponService couponService;
    @Autowired
    private MerchantService merchantService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private MemberCouponService memberCouponService;
    @Autowired
    private TradeService tradeService;

    /**
     * 会员h5扫码支付
     * @param ciphertext aes密文
     * @param encrypted rsa密文
     * @return
     */
    public Map<String, Object> h5Pay(String ciphertext, String encrypted){
        try {
            String payUrl = "";//支付地址
            String plainText = checkRequestData(ciphertext, encrypted);
            Map<String, Object> requestData = checkCouponAndGold(plainText);
            Double money = (Double) requestData.get("money");
            Long merchantId = (Long) requestData.get("merchantId");
            Trade trade = (Trade) requestData.get("trade");
            //如果金额大于0
            if (money > 0) {
                Merchant merchant = merchantService.selectMerchantById(merchantId);
                Map<String, String> map = new TreeMap<>();
                String datetime = DateUtils.formatDate(new Date(), "yyyyMMddHHmmss");
                //构建业务参数
                JSONObject bizContent = new JSONObject();
//                long out_trade_no = System.currentTimeMillis();
                bizContent.put("out_trade_no", trade.getOutTradeNo());
                bizContent.put("subject", merchant.getMerchantName()+"线下扫码订单");
                bizContent.put("total_fee", MyDecimalUtils.mul(money,100).intValue());
                bizContent.put("channel_type", "WX_JSAPI");//通道类型，扫码支付，WX_JSAPI,WX_NATIVE、ALI_QRCODE、微信小程序：WX_APPLET，微信代扣：WX_WITHHOLD，等具体见接口规则-参数规定-通道类型
                bizContent.put("client_ip", Inet4Address.getLocalHost().getHostAddress());
                bizContent.put("notify_url", "http://121.41.55.48:8777/api/notify/hyNotify");
                //构建公共参数
                map.put("method", "heemoney.pay.applypay");
                map.put("version", "1.0");
                map.put("app_id", merchant.getAppId());//应用ID，商户的应用id
                map.put("mch_uid", merchant.getMchUid());//商户统一编号
                map.put("charset", "UTF-8");
                map.put("timestamp", datetime);
                map.put("biz_content", bizContent.toJSONString());
                map.put("sign_type", "MD5");
                String sign = createSign(map,merchant.getMchKey());
                map.put("sign", sign);
                String url = "https://pay.heemoney.com/v1/ApplyPay";
                String s = JSON.toJSONString(map);
                String post = HttpClientUtils.post(url, s);
                JSONObject huiYuanObject = JSONObject.parseObject(post);
                payUrl = huiYuanObject.getString("hy_js_auth_pay_url");
                trade.setHyBillNo(huiYuanObject.getString("hy_bill_no"));
                if (payUrl == null) {
                    throw new BusinessException(BusinessErrorEnum.UNKNOWN_ERROR, "请求支付失败");
                }
            }
            tradeService.insertTrade(trade);
            HashMap<String, Object> resultMap = new HashMap<>();
            resultMap.put("payUrl",payUrl);
            resultMap.put("trade",trade);
            return resultMap;
        } catch (Exception e) {
            throw new BusinessException(BusinessErrorEnum.UNKNOWN_ERROR, "请求支付失败");
        }
    }

    /**
     * 生成签名
     *
     * @param map
     * @return
     */
    private String createSign(Map<String, String> map, String key) {
        String signStr = "";
        for (Map.Entry<String, String> entry : map.entrySet()) {
            String key1 = entry.getKey();
            String value = entry.getValue();
            signStr += key1 + "=" + value + "&";
        }
        signStr += "key=" + key;
        String sign = DigestUtils.md5Hex(signStr).toUpperCase();
        return sign;
    }

    /**
     * 校验前端传递的数据
     */
    private String checkRequestData(String ciphertext, String encrypted) throws Exception {
//        String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmegp0b+m5eWd7\n" +
//                "NExr7IRVHCHOfm5QAlrHHu5wVaRXsVll3HOL59b8oCP84V/fsU8uQyPjZ+jdiVfq\n" +
//                "AloIuqGohkLgvKYvek9DZw9aC/bQBkBUlzvjzDgDSCyfDddiCWaX9aANwfy9oY3S\n" +
//                "o0Gcp1HkKTkyAIxsoM761Aqp9+ft6Qqfx17MeFbkVuba9fkkOzbHG104+b/kf5pC\n" +
//                "pgxoSuEKeaizGp6H7UrSW0szMCqGgV/7QuXh+XYez9tBxZyMBPKPP29YlS4CnqrK\n" +
//                "kqoSUGVjzqNOCoWTbzdM1IzD/gzN+rWsEbQs0q8i8j0TfxJsonai96NSjcKEXVo2\n" +
//                "57puliv1AgMBAAECggEAEyAIHXJR7o3k9oF+mhN07HYr6BYcRDLRDPkfuWYNWEm2\n" +
//                "lH4sBBGhYCphmAaoRgGPsCfkcpaYaQMDR433m/Mc6UhrXHgvu1qYyoyHdffT5fgh\n" +
//                "4dXx+myWrsHW5nrnmIqt7503Qv1bNMnfiihZPE74mHan7HelqkEbJjO/+eDSE0G4\n" +
//                "BxdF6NbtDBTNBPsaXvI6XHvXNv4CvXqKe3XEUAiWNsaBuVX99uySBNZbaEpsprJ8\n" +
//                "3ebWIhvPAavrac/5jlywA0VxV2Ys1aPJRX1WsL7Qt0ifJweeQF9DP3voDGkOyDga\n" +
//                "zt2jImDrhIgNMN3gc7wakaKrF0Pp1IpRvOibhR0GwQKBgQDZ5LEvWc805mURrSgG\n" +
//                "I6TD71G4RMNThJSxQ44/Uu+92C+90GTZnF1ZJVhR4WKXUFz/wufX4hpS71B6T/58\n" +
//                "DhhaDlwhzOxLbOYAqAQUuxBSrwTxW8hhUuDNCvW2LFrIT6DikFrFWtstj6Xs50v0\n" +
//                "LLoEg9E5RmPLuxtjclM5/xaCMQKBgQDDl1/eCyojwoO7NXwYREPY/or9OnycviCQ\n" +
//                "/+aKRsxSPiGBnwWhHnqXwtP5moE1dtfI1KNo0gFOLnrjNvVbXyTsjrYPQm+m6voW\n" +
//                "Ucx+n+3XRICThslKGLj/kW33zScwL15P3LGpoDhinkuby6qFmDEhpezkdNsCKU7O\n" +
//                "o1CEdQ5xBQKBgFyN1e2lGm0ACKJviPbCoTRRLcc1/jo1sOtzJLMlSYy8jdr08EG3\n" +
//                "N7esM03kjPp1OmuxoMWE12WvHeI2pISRgCqQuvXok96eDTzuIX2k0BQvH8xeDkm4\n" +
//                "6KBwLVsKkC1SFabnZoc6Rqudvv9YaFz5urI8Q90uVyms+r9NSqjx/9+hAoGBAKux\n" +
//                "5CwM7O77P5xFNSwwMMb5m5TzlJQbqobevMfBonbHp64bpFttX/x8wIup/6apLn9T\n" +
//                "eib3wsGYt7NheTy+ZrFqDZOTpGOIfgS9xZ+aULTZo2zdszFiRnPCfCA9bRs1WbsN\n" +
//                "ZsAar6SShJi8znH7yZVaDHv3wJFDJbTrVDESeJzpAoGAbeF2MSmhPYXcpnzfKKSi\n" +
//                "rLad7y9vbnB6olLA90T6rzdh5uXhUBp2XaDeRsrU186NiZo8XPK98VztHGhvZS3z\n" +
//                "C0Ur9QR3XSGSi4Nsl2RgrM0igl0CTihLRw3l57k3MYVDQXpm6AEO4XW0Pa/ouY1v\n" +
//                "5Y9i3bunZUxrHnxrKymGHxI=\n";
        String privateKeyDir = "/cert/rsa/rsa_private.crt";
        InputStream path = this.getClass().getResourceAsStream(privateKeyDir);
        BufferedReader br = new BufferedReader(new InputStreamReader(path));
        String s = null;
        String result = "";
        while ((s = br.readLine()) != null) {
            result = result + "\n" + s;
        }
        br.close();
        String privateKey = result.trim();
        String password = RSAEncryptUtil.decrypt(encrypted, privateKey);
        String plainText = AESUtil.aesDecrypt(ciphertext, password);
        if (plainText == null) {
            throw new BusinessException(BusinessErrorEnum.UNKNOWN_ERROR, "参数校验失败");
        }
        return plainText;
    }

    /**
     * 判断数据用户优惠券和金币是否正确
     */

    public Map<String, Object> checkCouponAndGold(String plainText){
        JSONObject requestParam = JSONObject.parseObject(plainText);
        Member member = tokenService.getLoginUser(ServletUtils.getRequest()).getMember();
        Long couponId = new Long(requestParam.getString("memberCouponId"));
        Long merchantId = new Long(requestParam.getString("merchantId"));
        Double money = new Double(requestParam.getString("money"));
        Double originalPrice = money;
        Double useGoldNum = new Double(requestParam.getString("useGoldNum"));
        //如果用户使用了优惠券
        if (couponId > 0) {
            MemberCoupon memberCoupon = memberCouponService.selectMemberCouponById(couponId);
            if (memberCoupon.getStatus() != 1 || DateUtils.dateDiff(new Date(), memberCoupon.getExpireTime(),6) < 0) {
                throw new BusinessException(BusinessErrorEnum.UNKNOWN_ERROR,"优惠券已过期");
            }
            Coupon coupon = couponService.selectCouponById(memberCoupon.getCouponId());
            money = MyDecimalUtils.mul(money, coupon.getAmount());
        }
        //如果用户使用了金币抵扣
        if (useGoldNum > 0) {
            if (member.getGoldNum().doubleValue() < useGoldNum.doubleValue()) {
                throw new BusinessException(BusinessErrorEnum.UNKNOWN_ERROR,"用户金币不足");
            }
            money = MyDecimalUtils.sub(money, useGoldNum);
        }
        Trade trade = Trade.builder()
                .amount(originalPrice)
                .payerTotal(money)
                .outTradeNo(System.currentTimeMillis()+"")
                .memberId(member.getId())
                .merchantId(merchantId)
                .memberCouponId(couponId)
                .useGoldNum(useGoldNum)
                .createdTime(new Date())
                .build();
        HashMap<String, Object> map = new HashMap<>();
        map.put("money",money);
        map.put("merchantId",merchantId);
        map.put("trade",trade);
        return map;
    }
}
